// Producer Consumer Problem
// ml:ldf += -pthread
// ml:run = $bin < input
#include <iostream>
#include <array>
#include <thread>
#include <vector>
#include <string>
#include <condition_variable>
#include <atomic>
#include <mutex>

// exceptions
struct canceled {};

namespace v1
{
    struct cancelable_semaphore
    {
        void alloc()
        {
            std::unique_lock<std::mutex> _{m};
            cv.wait(_, [this] { return counter > 0 || (counter <= 0 && canceling); });
            if (canceling) throw canceled{};
            counter--;
        }

        void free(int amount = 1)
        {
            std::unique_lock<std::mutex> _{m};
            counter += amount;
            if (amount > 1) cv.notify_all();
            else cv.notify_one();
        }

        void cancel()
        {
            std::unique_lock<std::mutex> _{m};
            canceling = true;
            cv.notify_all();
        }

    private:
        int counter{};
        std::condition_variable cv;
        std::mutex m;
        std::atomic<bool> canceling{};
    };
}
using v1::cancelable_semaphore;

template <class T, int Capacity>
struct ring_buffer
{
    void push(T x)
    {
        queue[last] = std::move(x);
        last = (last + 1) % Capacity;
    }

    T pop()
    {
        auto x = queue[first];
        first = (first + 1) % Capacity;
        return x;
    }

private:
    std::array<T, Capacity> queue;
    int first{}, last{};
};

template <class T, int Capacity>
struct channel
{
    void write(T x)
    {
        nwrite.alloc();
        {
            std::lock_guard<std::mutex> _{m};
            queue.push(x);
        }
        nread.free();
    }

    T read()
    {
        nread.alloc();
        auto x = [this] {
            std::lock_guard<std::mutex> _{m};
            return queue.pop();
        } ();
        nwrite.free();
        return x;
    }

    void open_writer() { living_writer++; }
    void close_writer() { if (--living_writer == 0) cancel(); }
    void open_reader() { living_reader++; }
    void close_reader() { if (--living_reader == 0) cancel(); }

    void start()
    {
        nwrite.free(living_writer);
    }

    void cancel()
    {
        nwrite.cancel();
        nread .cancel();
    }

private:
    ring_buffer<int, Capacity> queue;
    cancelable_semaphore nwrite;
    cancelable_semaphore nread;
    std::mutex m;
    std::atomic<int> living_writer{};
    std::atomic<int> living_reader{};
};

bool is_prime(int n)
{
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) return false;
    return true;
}

int main()
{
    std::vector<std::thread> threads;
    std::mutex m_output;
    channel<int, 9> chn;
    std::string id, type;
    int first, last;
    while (std::cin >> id >> type >> first >> last) {
        if (type.size() != 1) return 1;
        switch (type[0]) {
            case 'D':
                chn.open_reader();
                threads.emplace_back([&chn, &m_output, id, count=first] () mutable {
                    try {
                        while (count--) {
                            auto x = chn.read();
                            std::lock_guard<std::mutex> _{m_output};
                            std::cerr << "\e[0;33mconsumer [" << id << "] got <" << x << ">\e[0m\n";
                        }
                    } catch (canceled const&) {}
                    chn.close_reader();
                });
                break;
            case 'W':
                chn.open_writer();
                threads.emplace_back([&chn, &m_output, id, first, last] {
                    try {
                        for (int n=first; n<last; n++) {
                            if (is_prime(n)) {
                                chn.write(n);
                                std::lock_guard<std::mutex> _{m_output};
                                std::cerr << "\e[1;32mproducer [" << id << "] put <" << n << ">\e[0m\n";
                            }
                        }
                    } catch (canceled const&) {}
                    chn.close_writer();
                });
                break;
            default: return 2;
        }
    }

    chn.start();
    for (auto& thread: threads)
        if (thread.joinable())
            thread.join();
}

